// spindle.js
// Contains Backbone.js models, views, controllers

$(function(){

Backbone.Model.prototype.getField = function () {
	var retVal = this.get('fields');
	for ( var i = 0; i < arguments.length; i++ ) {
		retVal = retVal[arguments[i]]
	}
	return retVal;
};

Backbone.Model.prototype.getExtra = function () {
	var retVal = this.get('extras');
	for ( var i = 0; i < arguments.length; i++ ) {
		retVal = retVal[arguments[i]]
	}
	return retVal;
};
	
window.Item = Backbone.Model.extend({
	initialize: function() {
		/*if (!this.get("name")) {
			this.set({"name": "empty item..."})
		}
		if (!this.get("content")) {
			this.set({"content": "no content..."})
		}*/
	},
			
	toggle: function() {
		this.save({done: !this.get("done")});
	},
	
	clear: function() {
		this.destroy();
		this.view.remove();
	}
});

window.ItemCollection = Backbone.Collection.extend({
	model: Item,
	url: "/api/item",
	initialize: function() {
		_.bindAll(this, "done", "remaining", "nextOrder", "comparator");
	},
	
	done: function() {
		return this.filter(function(item){ return item.get("done"); });
	},
	
	remaining: function() {
		return this.without.apply(this, this.done());
	},
	
	nextOrder: function() {
		if (!this.length) return 1;
		return this.last().get("order") + 1;
	},
	
	comparator: function(item) {
		if (this.list.ordering === undefined)
			return 0;
		var order = this.list.ordering[item.get('id')];
		return order;
	}
});

window.Photo = Backbone.Model.extend({
	initialize: function() {
	},
	
	clear: function() {
		this.destroy();
		this.view.remove();
	}
});

window.PhotoCollection = Backbone.Collection.extend({
	model: Photo,
	initialize: function(options) {
		if (options !== undefined) {
			this.url = options.url;
		}
	}
});

window.List = Backbone.Model.extend({
	// pass {id: [some_id]} in always
	// passed in items JSON, then use that to refresh items,
	// otherwise, fetch using id
	initialize: function() {
		this.items = new ItemCollection();
		this.items.list = this;
		this.photos = new PhotoCollection;
		
		if (this.isNew())
		{
			this.set({ title: "my new list"});
			//this.save();				
		}
		else
		{
			this.updateUrls();
			this.updateOrdering();
		}	
	},
	
	url: function() {
		if (this.id === undefined)
		{
			return "/api/list/";
		}
		else
		{
			return "/api/list/" + this.id;
		}
	},
	
	updateUrls: function() {
		this.set({ url: this.url() });
		this.updateOtherUrls();
	},
	
	updateOrdering: function() {
		var ord = this.get("ordering");
		// set ordering
		if (ord.length > 0) {
			var count = 0;
			this.ordering = _.reduce(ord.split(','), function(dict, num) {
				if (num.length == 0)
					return;
				count = count + 1;
				dict[num] = count;
				return dict;
			}, new Array());
		}		
	},
	
	updateOtherUrls: function() {
		this.items.url = this.url() + "/items/";
		this.photos.url = this.url() + "/photos/";
	}
});

window.MyListCollection = Backbone.Collection.extend({
	model: List,
	initialize: function(options) {
		this.url = "/api/user/" + options.username + "/lists";		
	}
});

window.ItemView = Backbone.View.extend({
	tagName: "li",
	events: {
		"click .check"					: "toggleDone",
		"dblclick div.item-name"		: "editContent",
		"click span.item-destroy"		: "clear",
		"keypress .edit-item-name"		: "updateNameOnEnter",
		"dblclick div.item-content"		: "editContent",
		"click .save"	: "saveItemFromEditor",
		"click .cancel"	: "cancelEditor"
	},
	
	initialize: function() {
		_.bindAll(this, "render", 
						"close",
						"toggleDone",
						"editContent", 
						"clear",
						"updateNameOnEnter",
						"saveItemFromEditor",
						"cancelEditor");
		this.model.bind("change", this.render);
		this.model.view = this;
		this.template = _.template($("#item-template").html());
		$(this.el).attr('id', "item-" + this.model.get('id'));
	},
	
	render: function() {
		if (this.editor === undefined) {
			$(this.el).html(this.template(this.model.toJSON()));
		}
		//this.setContent();
		this.setName();
		this.$(".save").hide();
		this.$(".cancel").hide();
		this.$(".edit-buttons").hide();
		return this;
	},
	
	setContent: function() {
		var content = this.model.get("content");
		this.$(".item-content").html(content);
		/*this.contentInput = this.$(".item-content-input");
		this.contentInput.bind("blur", this.close);
		this.contentInput.val(content);*/
	},
	
	setName: function() {
		var name = this.model.get("name");
		this.$(".item-name").text(name);
		this.nameInput = this.$(".edit-item-name");
		//this.nameInput.bind("blur", this.close);
		this.nameInput.val(name);
	},
	
	toggleDone: function() {
		this.model.toggle();
	},
	
	editName: function() {
		$(this.el).addClass("editing"); //$(this.el);
		this.nameInput.focus();
	},
	
	close: function(editingClassName) {
		/*this.nameInput.unbind();
		this.contentInput.unbind();*/
		this.model.save({name: this.nameInput.val(), content: this.editor.attr("value")}, {silent: true});
		$("#" + this.editorId).hide();
		$(this.el).removeClass(editingClassName);
		
		this.setContent();
		this.setName();
	},
	
	updateNameOnEnter: function(e) {
		if (e.keyCode == 13) this.close("editing");
	},
	
	saveItemFromEditor: function(e) {
		e.preventDefault();
		var cont = this.editor.attr("value").replace("<br _moz_editor_bogus_node=\"TRUE\" />", "");
		if (cont === "<br />")
		{
			cont = "";
		}
		this.model.set({name: this.nameInput.val(), content: cont}, {silent: true});
		
		//this.model.save({name: this.nameInput.val(), content: "hi", done: this.model.get("done")});
		//this.editor.attr("value", "");
		var that = this;
		this.model.save(this.model.attributes, {success : function(model, response) {
			$(that.el).removeClass("editing");
			that.$(".save").hide();
			that.$(".cancel").hide();
			that.$(".edit-buttons").hide();
			$("#" + that.editorId).hide();
		}});
		this.setContent();
		this.setName();
		$("#item-list").sortable("option", "disabled", false);
	},
	
	cancelEditor: function(e) {
		e.preventDefault();
		$(this.el).removeClass("editing");
		$("#" + this.editorId).hide();
		$("#item-list").sortable("option", "disabled", false);
	},
	
	editContent: function() {
		$(this.el).addClass("editing");
		//this.contentInput.focus();
		this.editorId = "item-editor" + this.model.get("id");
		this.$("#" + this.editorId).show();
    	if (this.editor === undefined || this.editor === null)
    	{
    		this.editor = new dijit.Editor({
    			styleSheets: "/appmedia/style.css;/appmedia/blog/style.css",
      			plugins: [
        			//"collapsibletoolbar",
        			//"fullscreen", "viewsource", "|",
        			"undo", "redo", "|",
        			"cut", "copy", "paste", "|",
        			"bold", "italic", "underline", "strikethrough", "|",
        			"insertOrderedList", "insertUnorderedList", "indent", "outdent", "|",
        			//"formatBlock", "fontName", "fontSize", "||",
        			//"findreplace", "insertEntity", "blockquote", "|",
        			"createLink", "insertImage", "insertanchor",// "|",
        			//"foreColor", "hiliteColor", "|",
        			//"showblocknodes", "pastefromword",
        			// headless plugins
        			//"normalizeindentoutdent", "prettyprint",
        			//"autourllink", "dijit._editor.plugins.EnterKeyHandling"
      			],
      			height: "200px"
    		}).placeAt(this.editorId, "first");
    	}
    	/*else
    	{
			this.editor.placeAt(this.editorId,"first");    
    	}*/
    	
    	$("#item-list").sortable("option", "disabled", true);
    	
    	this.$(".edit-buttons").show();
		this.$(".save").show();
    	this.$(".cancel").show();
    	
    	var editor = this.editor;
    	var model = this.model;
		this.editor.onLoadDeferred.addCallback(function() {
          editor.attr("value", model.get("content"));
        });
    	//this.editor.attr("value", this.model.get("content"));
	},
	
	remove: function() {
		$(this.el).remove();
	},
	
	clear: function() {
		// clear model then remove model from collection to update stats view
		// destroy first...otherwise model will not have url() which depends on its collection
		this.model.clear();
		if (this.model.list !== undefined) {
			this.model.list.items.remove(this.model);
		}
	}	
})

window.PhotoView = Backbone.View.extend({
	tagName: "li",
	className: "photo",
	events: {
		"click .photo-delete"	: "deletePhoto",
		"mouseenter"	: "showEdit",
		"mouseleave"	: "hideEdit"
	},
	
	initialize: function() {
		//_.bindAll(this, "render", "loadListContents", "deleteList", "showEdit", "hideEdit");
		this.model.bind("change", this.render);
		this.model.view = this;
		this.template = _.template($("#photo-template").html())
	},
	
	render: function() {
		$(this.el).html(this.template(this.model.toJSON()));
		return this;
	},
	
	deletePhoto: function(e) {
		//this.model.destroy();
		//this.remove();
		//this.onDeleteList(this.model);
		this.confirmDelete();
		e.preventDefault();
	},
	
	showEdit: function(e) {
		this.$(".edit").show();
	},
	
	hideEdit: function(e) {
		this.$(".edit").hide();
	},

	confirmDelete: function() {
		var that = this;
		$('#confirm').modal({
			closeHTML: "<a href='#' title='Close' class='modal-close'>x</a>",
			position: ["20%",],
			overlayId: 'confirm-overlay',
			containerId: 'confirm-container', 
			onShow: function (dialog) {
				var modal = this;

				// if the user clicks "yes"
				$('.yes', dialog.data[0]).click(function () {
					// call the callback
					//if ($.isFunction(callback)) {
					//	callback.apply();
					//}
					that.model.destroy();
					that.remove();
					// close the dialog
					modal.close(); // or $.modal.close();
				});
			}
		});
	},
	
	remove: function() {
		$(this.el).remove();
	}
}),

window.ListLinkView = Backbone.View.extend({
	tagName: "li",
	events: {
		"click"		: "loadListContents",
		"click .edit"		: "loadListContents",
		"click .delete"	: "deleteList",
		"mouseover"	: "showEdit",
		"mouseout"	: "hideEdit"
	},
	
	initialize: function() {
		_.bindAll(this, "render", "loadListContents", "deleteList", "showEdit", "hideEdit");
		this.template = _.template($("#list-link-template").html())
		this.model.bind("change", this.render);
		this.model.view = this;
	},
	
	render: function() {
		$(this.el).html(this.template(this.model.toJSON()));
		$(this.el).addClass("list-link");
		return this;
	},

	loadListContents: function(e) {
		e.preventDefault();
		this.onOpenList(this.model);
	},
	
	deleteList: function(e) {
		//this.model.destroy();
		//this.remove();
		//this.onDeleteList(this.model);
		this.confirmDelete();
		e.preventDefault();
	},
	
	showEdit: function(e) {
		this.$(".edit").show();
	},
	
	hideEdit: function(e) {
		this.$(".edit").hide();
	},

	confirmDelete: function() {
		var that = this;
	$('#confirm').modal({
		closeHTML: "<a href='#' title='Close' class='modal-close'>x</a>",
		position: ["20%",],
		overlayId: 'confirm-overlay',
		containerId: 'confirm-container', 
		onShow: function (dialog) {
			var modal = this;

			// if the user clicks "yes"
			$('.yes', dialog.data[0]).click(function () {
				// call the callback
				//if ($.isFunction(callback)) {
				//	callback.apply();
				//}
				that.model.destroy();
				that.remove();
				that.onDeleteList(that.model);
				// close the dialog
				modal.close(); // or $.modal.close();
			});
		}
	});
}
}),

window.PhotoCollectionView = Backbone.View.extend({
	initialize: function(options) {
		_.bindAll(this, "render", "addOne", "addAll", "clear");
		
		this.el = $("#photos");
		this.photos = new PhotoCollection({ "url": options.url });
		this.photos.bind("add", this.addOne);
		this.photos.bind("refresh", this.addAll);
		this.photos.bind("all", this.render);
		this.photos.fetch();
	},
	
	addOne: function(photo) {
		var view = new PhotoView({"model": photo});
		$(this.el).append(view.render().el);
	},
	
	addAll: function() {
		this.photos.each(this.addOne);
		this.options.onPhotoLoaded.apply();
	},
	
	clear: function() {
		this.photos.each(function(photo) { photo.view.remove(); })
	}
}),

window.MyListCollectionView = Backbone.View.extend({
	el: $("#my-lists"),
	initialize: function(options) {
		_.bindAll(this, "render", "addOne", "addAll", "addOnOpenListListener");
		
		this.lists = new MyListCollection({ "username": options.username });
		this.lists.bind("add", this.addOne);
		this.lists.bind("refresh", this.addAll);
		this.lists.bind("all", this.render);
		this.lists.fetch();
		
	},
	
	addOne: function(list) {
		var view = new ListLinkView({"model": list});
		view.onOpenList = this.onOpenListListener;
		view.onDeleteList = this.onDeleteListListener;
		$(this.el).append(view.render().el);
	},
	
	addAll: function() {
		this.lists.each(this.addOne);
	},
	
	addOnOpenListListener: function(fun) {
		this.onOpenListListener = fun;
	},
	
	addOnDeleteListListener: function(fun) {
		this.onDeleteListListener = fun;
	},
	
	add: function(list) {
		this.lists.add(list);
	}
}),

window.ListBuilderView = Backbone.View.extend({
	el: $("#list-builder"),
	events: {
		"keypress #new-item": "createOnEnter",
		//"keyup #new-item": "showTooltip",
		"click .item-clear a": "clearCompleted",
		"dblclick .list-title"	: "editTitle",
		"keypress #title-input"		: "updateTitleOnEnter",
		"click #create-item .new-item"	: "enableItemCreation",
		"click .save-new-item"	: "saveItemFromEditor",
		"click .cancel-new-item"	: "cancelEditor"
	},
	
	initialize: function(options) {
		
		this.statsTemplate = _.template($("#stats-template").html())
		this.mainTemplate = _.template($("#list-builder-template").html())
				
		_.bindAll(this, 
						"addOne", 
						"addAll", 
						"render",
						"renderStats",
						"remove",  
						"editTitle", 
						"closeTitleInput", 
						"updateTitleOnEnter",
						"enableItemCreation",
						"saveItemFromEditor",
						"cancelEditor",
						"onOrderChanged",
						"onPhotoLoaded"
		);
		
		if (options === null || options === undefined ||
			options.list === null || options.list === undefined)
		{
			return;
		}
		
		this.list = options.list;
		
		this.render();
		
		this.input = this.$("#new-item");
		
		this.list.items.bind("add", this.addOne);
		this.list.items.bind("refresh", this.addAll);
		this.list.items.bind("all", this.renderStats);
					
		$("#item-list").sortable({
			revert: true,
			update: this.onOrderChanged,
			opacity: 1
		});
		
		this.photosView = new PhotoCollectionView({ "url" : this.list.photos.url, "onPhotoLoaded" : this.onPhotoLoaded });
				
		this.titleInput = $("#title-input");
		this.titleInput.html(this.list.get("title"))
		this.titleInput.bind("blur", this.closeTitleInput);
		
		this.$("#editor .edit-buttons").hide();
		this.$(".save-new-item").hide();
		this.$(".cancel-new-item").hide();
		
		dojo.addClass(dojo.body(), "claro");
		
		// if list is on server already, fetch items
		if (!this.list.isNew()) {
			this.list.items.fetch();
			
			// fetch images
			//this.list.photos.fetch();
		}
	},
	
	render: function() {
		this.$(this.el).html(this.mainTemplate({
			title: this.list.get("title"),
		}));
	},
	
	onPhotoLoaded: function() {
		
		var uploader = new plupload.Uploader({
			runtimes : 'html5',
			browse_button : 'pick-files',
			max_file_size : '10mb',
			url : 'api/upload/photo/list/' + this.list.id,
			filters : [
				{title : "Image files", extensions : "jpg,gif,png"},
				{title : "Zip files", extensions : "zip"}
			]
			,resize : {width : 640, height : 480, quality : 90}
		});

		uploader.bind('Init', function(up, params) {
			//$('#filelist').html("<div>Current runtime: " + params.runtime + "</div>");
		});
		
		$('#uploadfiles').click(function(e) {
			uploader.start();
			e.preventDefault();
		});

		uploader.init();

		uploader.bind('FilesAdded', function(up, files) {
			$.each(files, function(i, file) {
				$('#filelist').append(
					'<div id="' + file.id + '">' +
					file.name + ' (' + plupload.formatSize(file.size) + ') <b></b>' +
					'</div>');
			});
			uploader.start();
			up.refresh(); // Reposition Flash/Silverlight
		});

		uploader.bind('UploadProgress', function(up, file) {
			$('#' + file.id + " b").html(file.percent + "%");
		});

		uploader.bind('Error', function(up, err) {
			$('#filelist').append("<div>Error: " + err.code +
				", Message: " + err.message +
				(err.file ? ", File: " + err.file.name : "") +
				"</div>"
			);

			up.refresh(); // Reposition Flash/Silverlight
		});
		
		var that = this;
		uploader.bind('FileUploaded', function(up, file) {
			$('#' + file.id + " b").html("100%");
			
			// refresh photoCollection
			that.photosView.clear();
			that.photosView.photos.fetch();

			that.uploader.refresh();
		});
		
		this.uploader = uploader;
		this.uploader.refresh();
		
		var that = this;
		$(window).resize(function() {
			if (that.uploader !== undefined)
				that.uploader.refresh();
		})
	},
	
	renderStats: function() {		
		this.$("#item-stats").html(this.statsTemplate({
			total: this.list.items.length,
			done: this.list.items.done().length,
			remaining: this.list.items.remaining().length
		}));
	},
	
	addOne: function(item) {
		var view = new ItemView({model: item});
		item.list = this.list;
		this.$("#item-list").append(view.render().el);
		
		this.onOrderChanged(null, null);
	},
	
	addAll: function() {
		$("#item-list").html("");
		this.list.items.each(this.addOne);
	},
	
	remove: function(item) {
		this.list.items.each(function (item) {
			if (item.view !== undefined)
			{
				item.view.remove();
			}
		});		
	},
	
	newAttributes: function() {
		var cont = this.editor.attr("value").replace("<br _moz_editor_bogus_node=\"TRUE\" />", "");
		return {
			name: this.input.val(),
			order: this.list.items.nextOrder(),
			content: cont,
			done: false
		};
	},
	
	createOnEnter: function(e) {
		if (e.keyCode != 13) return;
		this.list.items.create(this.newAttributes());
		this.input.val("");
		this.editor.attr("value", "");
		this.$("#create-item").removeClass("editing");
		this.$("#editor").hide();
	},
	
	clearCompleted: function() {
		var that = this;
		_.each(this.list.items.done(), function(item){ 
			item.clear();
			that.list.items.remove(item); 
		});
	},
	
	showTooltip: function(e) {
		var tooltip = this.$(".ui-tooltip-top");
		var val = this.input.val();
		tooltip.fadeOut();
		if (this.tooltipTimeout) clearTimeout(this.tooltipTimeout);
		if (val == "" || val == this.input.attr("placeholder")) return;
		var show = function() { tooltip.show().fadeIn(); };
		this.tooltipTimeout = _.delay(show, 1000);
	},
	
	toggleDone: function() {
		this.model.toggle();
	},
	
	editTitle: function() {
		this.$(".list-title").addClass("editing");
		this.titleInput.focus();
	},
	
	closeTitleInput: function() {
		this.list.save({title: this.titleInput.val()});
		//this.model.set({content: this.input.val()});
		this.$(".list-title").removeClass("editing");
		this.$(".list-title h1").html(this.titleInput.val());
	},
		
	updateTitleOnEnter: function(e) {
		if (e.keyCode == 13) this.closeTitleInput();
	},
	
	saveItemFromEditor: function(e) {
		e.preventDefault();
		this.list.items.create(this.newAttributes());
		this.input.val("");
		this.editor.attr("value", "");
		this.$("#create-item").removeClass("editing");
		this.$("#editor").hide();
	},
	
	cancelEditor: function(e) {
		e.preventDefault();
		this.$("#create-item").removeClass("editing");
		this.$("#editor").hide();
	},
	
	onOrderChanged: function(event, ui) {
		// save ordering to server
		if ($('#item-list li').length > 1) {
			var result = $('#item-list').sortable('toArray');
			var commaDelimitedIds = _.reduce(result, function(memo, item_id) { return memo.concat(item_id.slice(5).concat(",")) }, "");
			var cleanOrdering = commaDelimitedIds.slice(0, commaDelimitedIds.lastIndexOf(','));
			this.list.save({ordering: cleanOrdering});
			this.list.updateOrdering();
		}
	},
	
	enableItemCreation: function(e) {
		e.preventDefault();
		this.$("#create-item").addClass("editing");
		this.$("#new-item").focus();
		//$("#create-item-block").append($("#editor"));
		this.$("#editor").show();
    	if (this.editor === undefined)
    	{
    		this.editor = new dijit.Editor({
    			styleSheets: "/appmedia/style.css;/appmedia/blog/style.css",
      			plugins: [
        			//"collapsibletoolbar",
        			//"fullscreen", "viewsource", "|",
        			"undo", "redo", "|",
        			"cut", "copy", "paste", "|",
        			"bold", "italic", "underline", "strikethrough", "|",
        			"insertOrderedList", "insertUnorderedList", "indent", "outdent", "|",
        			//"formatBlock", "fontName", "fontSize", "||",
        			//"findreplace", "insertEntity", "blockquote", "|",
        			"createLink", "insertImage", "insertanchor",// "|",
        			//"foreColor", "hiliteColor", "|",
        			//"showblocknodes", "pastefromword",
        			// headless plugins
        			//"normalizeindentoutdent", "prettyprint",
        			//"autourllink", "dijit._editor.plugins.EnterKeyHandling"
      			],
      			height: "200px"
    		}).placeAt("editor", "first");
    	}
    	
    	this.$(".save-new-item").show();
    	this.$(".cancel-new-item").show();
    	this.$("#editor .edit-buttons").show();
    	
		/*var textareas = dojo.query("textarea");
  		if(textareas && textareas.length){
    		dojo.addClass(dojo.body(), "claro");
    		textareas.instantiate(dijit.Editor, {
      			styleSheets: "/appmedia/style.css;/appmedia/blog/style.css",
      			plugins: [
        			"collapsibletoolbar",
        			"fullscreen", "viewsource", "|",
        			"undo", "redo", "|",
        			"cut", "copy", "paste", "|",
        			"bold", "italic", "underline", "strikethrough", "|",
        			"insertOrderedList", "insertUnorderedList", "indent", "outdent", "||",
        			"formatBlock", "fontName", "fontSize", "||",
        			"findreplace", "insertEntity", "blockquote", "|",
        			"createLink", "insertImage", "insertanchor", "|",
        			"foreColor", "hiliteColor", "|",
        			"showblocknodes", "pastefromword",
        			// headless plugins
        			"normalizeindentoutdent", "prettyprint",
        			"autourllink", "dijit._editor.plugins.EnterKeyHandling"
      			]
    		});
  		}*/
	},
})
});